package tp.pr5.instructions;

import tp.pr5.Constants;
import tp.pr5.NavigationModule;
import tp.pr5.RobotEngine;
import tp.pr5.instructions.exceptions.InstructionExecutionException;
import tp.pr5.instructions.exceptions.WrongInstructionFormatException;
import tp.pr5.items.ItemContainer;

/**
 * This instruction tries to pick an Item from the current place and puts it the robot inventory. This instruction works if the user writes PICK id or COGER id
 */
public class PickInstruction implements Instruction {
	private NavigationModule navigation;
	private ItemContainer robotContainer;
	private RobotEngine robot;
	private String id;
	
	/**
	 * It builds a default PickInstruction
	 */
	public PickInstruction()
	{}
	
	/**
	 * It builds a PickInstruction
	 * @param id
	 */
	public PickInstruction(String id)
	{
		this.id = id;
	}
	@Override
	/**
	 * Parses the String returning an instance of PickInstruction or throwing a WrongInstructionFormatException()
	 * @param cad - text String to parse
	 * @return Instruction Reference to an instance of PickInstruction
	 * @throws WrongInstructionFormatException - hen the String is not 
	 */
	public Instruction parse(String cad) throws WrongInstructionFormatException {
		String[] commands;
		commands = cad.split(" ");
		
		if (commands[0].equalsIgnoreCase("PICK") || commands[0].equalsIgnoreCase("COGER"))
		{
			if (commands.length >= 2 )
			{
				return new PickInstruction(commands[1]);
			}
			else
				throw new WrongInstructionFormatException();
		}
		else
			throw new WrongInstructionFormatException();
	}

	@Override
    /**
     * Returns a description of the Instruction syntax. The string does not end with the line separator. It is up to the caller adding it before printing.
     * @return The Instruction's syntax.
     */
	public String getHelp() {
		return "PICK|COGER <id>";
	}

	@Override
	/**
	 * Set the execution context. The method receives the entire engine (engine, navigation and the robot container) even though the actual implementation of execute() may not require it.
	 * @param engine - The robot engine
	 * @param navigation - The information about the game, i.e., the places, current direction and current heading to navigate
	 * @param robotContainer - The inventory of the robot
	 */
	public void configureContext(RobotEngine engine, NavigationModule navigation, ItemContainer robotContainer) {
		this.robotContainer = robotContainer;
		this.navigation = navigation;
		this.robot = engine;
	}

	@Override
	/**
	 * The robot adds an item to its inventory from the current place, if it exists
	 * @throws instructionExecutionException - When the place does not contain an item with this name or when there is another item with the same id in the robot inventory
	 * @throws InstructionExecutionException - if there exist any execution error.
	 */
	public void execute() throws InstructionExecutionException {

		if (this.robotContainer.containsItem(this.id))
		{
			throw new InstructionExecutionException(Constants.MESSAGE_SAYS + Constants.MESSAGE_PICK_ERROR1 + this.id.toLowerCase());
		}
		else if (!navigation.findItemAtCurrentPlace(this.id))
		{
			throw new InstructionExecutionException(Constants.MESSAGE_SAYS + "There isn't " + this.id.toLowerCase() + " in this place");
		}
		else
		{
			this.robotContainer.addItem(this.navigation.getCurrentPlace().pickItem(this.id));
			this.robot.saySomething(Constants.MESSAGE_SAYS + Constants.MESSAGE_PICK_OK + this.id + Constants.LINE_SEPARATOR);
		}
	}
}
